<?php

declare(strict_types=1);

namespace Plugin\Attractions\AttractionManagement\Repository;

use App\Exception\BusinessException;
use App\Http\Common\ResultCode;
use App\Repository\IRepository;
use Common\Common;
use Hyperf\Collection\Arr;
use Hyperf\Database\Model\Builder;
use Plugin\Attractions\AttractionManagement\Model\AttractionScore;
use Ramsey\Uuid\Type\Decimal;

class AttractionScoreRepository extends IRepository
{
    public function __construct(
        protected readonly AttractionScore $model, 
        protected readonly AttractionSpotRepository $spotRepository,
    ) {}

    const TOTAL_SCORE_KEY = 'attraction:score:total';

    const SCORE_COUNT_KEY = 'attraction:score:count';

    public function handleSearch(Builder $query, array $params): Builder
    {
        return $query
            ->when(Arr::get($params, 'id'), static function (Builder $query, $id) {
                $query->whereIn('id', Arr::wrap($id));
            })
            ->when(Arr::get($params, 'spotId'), static function (Builder $query, $type) {
                return $query->whereIn('spot_id', Arr::wrap($type));
            })
            ->when(Arr::get($params, 'userId'), static function (Builder $query, $type) {
                return $query->whereIn('user_id', Arr::wrap($type));
            });
    }

    public function create(array $data): mixed
    {
        $userId = $data['user_id'];
        $spotId = $data['spot_id'];
        $score = intval($data['score']);
        if ($this->model->where('user_id', $userId)->where('spot_id', $spotId)->exists()) {
            throw new BusinessException(ResultCode::UNPROCESSABLE_ENTITY, trans('attraction-management.spot.score.exist'));
        }
        $redis = Common::redis();
        $redis->hIncrBy(self::TOTAL_SCORE_KEY, strval($spotId), $score);
        $redis->hIncrBy(self::SCORE_COUNT_KEY, strval($spotId), 1);
        return $this->model->create($data);
    }

    public function statisticScore(){
        $ids = $this->spotRepository->getIds([]);
        $redis = Common::redis();
        foreach ($ids as $id) {
            $TotalScore = $this->model->where('spot_id', $id)->sum('score');
            $scoreCount = $this->model->where('spot_id', $id)->count();
            $redis->hSet(self::TOTAL_SCORE_KEY, strval($id), $TotalScore);
            $redis->hSet(self::SCORE_COUNT_KEY, strval($id), $scoreCount);
        }
    }

    public function getScore(int $spotId): string
    {
        $redis = Common::redis();
        $spotId = strval($spotId);
        $totalScore = $redis->hGet(self::TOTAL_SCORE_KEY, $spotId);
        $scoreCount = $redis->hGet(self::SCORE_COUNT_KEY, $spotId);
        try {
            return bcdiv($totalScore, $scoreCount, 1);
        } catch (\Throwable $e) {
            return '5.0';
        }
    }

    public function getScoreList(array $params = []): array
    { 
        $redis = Common::redis();
        $score = $redis->hGetAll(self::TOTAL_SCORE_KEY);
        $count = $redis->hGetAll(self::SCORE_COUNT_KEY);
        $result = [];
        foreach ($score as $key => $value) {
            if (!empty($params) && !in_array($key, $params['ids'])) {
                continue;
            }
            try {
                $result[$key] = bcdiv($value, $count[$key], 1);
            } catch (\Throwable $e) {
                $result[$key] = '5.0';
            }
        }
        return $result;
    }
}
